/*
 * Copyright 2017 Zhihu Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.xiaoyu.media.matisse.ui

import android.app.Activity
import android.content.Intent
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.widget.Toolbar
import android.view.MenuItem
import android.view.View
import android.widget.AdapterView
import android.widget.CompoundButton
import android.widget.TextView
import com.xiaoyu.media.matisse.internal.entity.Album
import com.xiaoyu.media.matisse.internal.entity.Item
import com.xiaoyu.media.matisse.internal.entity.SelectionResult
import com.xiaoyu.media.matisse.internal.entity.SelectionSpec
import com.xiaoyu.media.matisse.internal.model.AlbumCollection
import com.xiaoyu.media.matisse.internal.model.SelectedItemCollection
import com.xiaoyu.media.matisse.internal.ui.AlbumPreviewActivity
import com.xiaoyu.media.matisse.internal.ui.BasePreviewActivity
import com.xiaoyu.media.matisse.internal.ui.MediaSelectionFragment
import com.xiaoyu.media.matisse.internal.ui.SelectedPreviewActivity
import com.xiaoyu.media.matisse.internal.ui.adapter.AlbumMediaAdapter
import com.xiaoyu.media.matisse.internal.ui.adapter.AlbumsAdapter
import com.xiaoyu.media.matisse.internal.ui.widget.AlbumsSpinner
import com.xiaoyu.media.matisse.internal.utils.MediaStoreCompat
import com.xiaoyu.media.matisse.internal.utils.PhotoMetadataUtils
import com.xiaoyu.media.R

/**
 * Main Activity to display albums and media content (images/videos) in each album
 * and also support media selecting operations.
 */
class MatisseActivity : AppCompatActivity(), AlbumCollection.AlbumCallbacks, AdapterView.OnItemSelectedListener, MediaSelectionFragment.SelectionProvider, View.OnClickListener, AlbumMediaAdapter.CheckStateListener, AlbumMediaAdapter.OnMediaClickListener, AlbumMediaAdapter.OnPhotoCapture, CompoundButton.OnCheckedChangeListener {

    private val mAlbumCollection = AlbumCollection()
    private var mMediaStoreCompat: MediaStoreCompat? = null
    private val mSelectedCollection = SelectedItemCollection(this)
    private var mSpec: SelectionSpec = SelectionSpec.instance

    private var mAlbumsSpinner: AlbumsSpinner? = null
    private var mAlbumsAdapter: AlbumsAdapter? = null
    private var mButtonPreview: TextView? = null
    private var mButtonApply: TextView? = null
    private var mButtonOriginal: MatisseRadioButton? = null
    private var mContainer: View? = null
    private var mEmptyView: View? = null

    private var mOriginalEnable: Boolean = false
    private var mOriginalChecked: Boolean = false

    override fun onCreate(savedInstanceState: Bundle?) {
        // programmatically set theme before super.onCreate()
        mSpec = SelectionSpec.instance
        setTheme(mSpec.themeId)
        super.onCreate(savedInstanceState)
        if (!mSpec.hasInited) {
            setResult(Activity.RESULT_CANCELED)
            finish()
            return
        }
        setContentView(R.layout.matisse_activity_matisse)

        if (mSpec.needOrientationRestriction()) {
            requestedOrientation = mSpec.orientation
        }

        if (mSpec.capture) {
            mMediaStoreCompat = MediaStoreCompat(this)
            if (mSpec.captureStrategy == null)
                throw RuntimeException("Don't forget to set CaptureStrategy.")
            mSpec.captureStrategy?.let { mMediaStoreCompat?.setCaptureStrategy(it) }
        }

        val toolbar = findViewById<Toolbar>(R.id.toolbar)
        setSupportActionBar(toolbar)
        val actionBar = supportActionBar
        actionBar?.setDisplayShowTitleEnabled(false)
        actionBar?.setDisplayHomeAsUpEnabled(true)
        //  Drawable navigationIcon = toolbar.getNavigationIcon();
        //  TypedArray ta = getTheme().obtainStyledAttributes(new int[]{R.attr.album_element_color});
        //  int color = ta.getColor(0, 0);
        //  ta.recycle();
        //  navigationIcon.setColorFilter(color, PorterDuff.Mode.SRC_IN);

        mButtonPreview = findViewById(R.id.button_preview)
        mButtonApply = findViewById(R.id.button_apply)
        mButtonOriginal = findViewById(R.id.button_original)
        mButtonPreview?.setOnClickListener(this)
        mButtonApply?.setOnClickListener(this)
        mButtonOriginal?.setOnCheckedChangeListener(this)
        mContainer = findViewById(R.id.container)
        mEmptyView = findViewById(R.id.empty_view)

        mSelectedCollection.onCreate(savedInstanceState)
        mOriginalEnable = savedInstanceState?.getBoolean(EXTRA_RESULT_ORIGINAL_ENABLE)
                ?: mSpec.originalable
        mOriginalChecked = savedInstanceState?.getBoolean(CHECK_STATE) ?: false
        mButtonOriginal?.visibility = if (mOriginalEnable) View.VISIBLE else View.GONE
        mButtonOriginal?.isChecked = mOriginalChecked
        updateBottomToolbar()

        mAlbumsAdapter = AlbumsAdapter(this, null, false)
        mAlbumsSpinner = AlbumsSpinner(this)
        mAlbumsSpinner?.setOnItemSelectedListener(this)
        mAlbumsSpinner?.setSelectedTextView(findViewById<View>(R.id.selected_album) as TextView)
        mAlbumsSpinner?.setPopupAnchorView(findViewById(R.id.selected_album))
        mAlbumsAdapter?.let { mAlbumsSpinner?.setAdapter(it) }
        try {
            mAlbumCollection.onCreate(this, this)
            mAlbumCollection.onRestoreInstanceState(savedInstanceState)
            mAlbumCollection.loadAlbums()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        mSelectedCollection.onSaveInstanceState(outState)
        mAlbumCollection.onSaveInstanceState(outState)
        outState.putBoolean(EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable)
        outState.putBoolean(CHECK_STATE, mOriginalChecked)
    }

    override fun onDestroy() {
        super.onDestroy()
        mAlbumCollection.onDestroy()
        mSpec.onCheckedListener = null
        mSpec.onSelectedListener = null
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        if (item.itemId == android.R.id.home) {
            onBackPressed()
            return true
        }
        return super.onOptionsItemSelected(item)
    }

    override fun onBackPressed() {
        setResult(Activity.RESULT_CANCELED)
        super.onBackPressed()
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode != Activity.RESULT_OK)
            return

        if (requestCode == REQUEST_CODE_PREVIEW) {
            mOriginalEnable = data?.getBooleanExtra(BasePreviewActivity.EXTRA_RESULT_ORIGINAL_ENABLE, false)
                    ?: false
            mOriginalChecked = data?.getBooleanExtra(BasePreviewActivity.CHECK_STATE, false)
                    ?: false
            val resultBundle = data?.getBundleExtra(BasePreviewActivity.EXTRA_RESULT_BUNDLE)
            val selectedItems = resultBundle?.getParcelableArrayList<Item>(SelectedItemCollection.STATE_SELECTION)
            val collectionType = resultBundle?.getInt(SelectedItemCollection.STATE_COLLECTION_TYPE, SelectedItemCollection.COLLECTION_UNDEFINED)
            if (data?.getBooleanExtra(BasePreviewActivity.EXTRA_RESULT_APPLY, false) == true) {
                val result = Intent()
                result.putExtra(EXTRA_RESULT_SELECTION, SelectionResult.createFromItemList(this, selectedItems?.toList()))
                result.putExtra(EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable)
                result.putExtra(CHECK_STATE, mOriginalChecked)
                setResult(Activity.RESULT_OK, result)
                finish()
            } else {
                selectedItems?.let { collectionType?.let { it1 -> mSelectedCollection.overwrite(it, it1) } }
                val mediaSelectionFragment = supportFragmentManager.findFragmentByTag(
                        MediaSelectionFragment::class.java.simpleName)
                if (mediaSelectionFragment is MediaSelectionFragment) {
                    mediaSelectionFragment.refreshMediaGrid()
                }
                updateBottomToolbar()
            }
        } else if (requestCode == REQUEST_CODE_CAPTURE) {
            // Just pass the data back to previous calling Activity.
            val contentUri = mMediaStoreCompat?.currentPhotoUri ?: Uri.EMPTY
            val path = mMediaStoreCompat?.currentPhotoPath ?: ""

            val intent = Intent()
            intent.putExtra(EXTRA_RESULT_SELECTION, SelectionResult.createFromCapture(path))
            intent.putExtra(EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable)
            intent.putExtra(CHECK_STATE, mOriginalChecked)
            setResult(Activity.RESULT_OK, intent)
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
                this@MatisseActivity.revokeUriPermission(contentUri,
                        Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
            finish()
        }
    }

    private fun updateBottomToolbar() {
        val selectedCount = mSelectedCollection.count()
        if (selectedCount == 0) {
            mButtonPreview?.isEnabled = false
            mButtonApply?.isEnabled = false
            mButtonApply?.text = getString(R.string.button_sure_default)
        } else if (selectedCount == 1 && mSpec.singleSelectionModeEnabled()) {
            mButtonPreview?.isEnabled = true
            mButtonApply?.setText(R.string.button_sure_default)
            mButtonApply?.isEnabled = true
        } else {
            mButtonPreview?.isEnabled = true
            mButtonApply?.isEnabled = true
            mButtonApply?.text = getString(R.string.button_sure, selectedCount)
        }
    }

    private fun countOverMaxSize(): Int {
        var count = 0
        val selectedCount = mSelectedCollection.count()
        for (i in 0 until selectedCount) {
            val item = mSelectedCollection.asList()[i]

            if (item.isImage) {
                val size = PhotoMetadataUtils.getSizeInMB(item.size)
                if (size > mSpec.originalMaxSize) {
                    count++
                }
            }
        }
        return count
    }

    override fun onClick(v: View) {
        if (v.id == R.id.button_preview) {
            val intent = Intent(this, SelectedPreviewActivity::class.java)
            intent.putExtra(BasePreviewActivity.EXTRA_DEFAULT_BUNDLE, mSelectedCollection.dataWithBundle)
            intent.putExtra(BasePreviewActivity.EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable)
            intent.putExtra(BasePreviewActivity.CHECK_STATE, mOriginalChecked)
            startActivityForResult(intent, REQUEST_CODE_PREVIEW)
        } else if (v.id == R.id.button_apply) {
            val result = Intent()
            result.putExtra(EXTRA_RESULT_SELECTION, SelectionResult.createFromItemList(this, mSelectedCollection.asList()))
            result.putExtra(EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable)
            result.putExtra(CHECK_STATE, mOriginalChecked)
            setResult(Activity.RESULT_OK, result)
            finish()
        }
    }

    override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) {
        mOriginalChecked = isChecked
    }

    override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
        mAlbumCollection.setStateCurrentSelection(position)
        mAlbumsAdapter?.cursor?.moveToPosition(position)
        val album = mAlbumsAdapter?.cursor?.let { Album.valueOf(it) }
        if (album?.isAll == true && SelectionSpec.instance.capture) {
            album.addCaptureCount()
        }
        album?.let { onAlbumSelected(it) }
    }

    override fun onNothingSelected(parent: AdapterView<*>) {
    }

    override fun onAlbumLoad(cursor: Cursor) {
        mAlbumsAdapter?.swapCursor(cursor)
        // select default album.
        val handler = Handler(Looper.getMainLooper())
        handler.post {
            cursor.moveToPosition(mAlbumCollection.currentSelection)
            mAlbumsSpinner?.setSelection(this@MatisseActivity,
                    mAlbumCollection.currentSelection)
            val album = Album.valueOf(cursor)
            if (album.isAll && SelectionSpec.instance.capture) {
                album.addCaptureCount()
            }
            onAlbumSelected(album)
        }
    }

    override fun onAlbumReset() {
        mAlbumsAdapter?.swapCursor(null)
    }

    private fun onAlbumSelected(album: Album) {
        if (album.isAll && album.isEmpty) {
            mContainer?.visibility = View.GONE
            mEmptyView?.visibility = View.VISIBLE
        } else {
            mContainer?.visibility = View.VISIBLE
            mEmptyView?.visibility = View.GONE
            val fragment = MediaSelectionFragment.newInstance(album)
            supportFragmentManager
                    .beginTransaction()
                    .replace(R.id.container, fragment, MediaSelectionFragment::class.java.simpleName)
                    .commitAllowingStateLoss()
        }
    }

    override fun onUpdate() {
        // notify bottom toolbar that check state changed.
        updateBottomToolbar()

        if (mSpec.onSelectedListener != null) {
            mSpec.onSelectedListener?.onSelected(
                    mSelectedCollection.asListOfUri(), mSelectedCollection.asListOfString())
        }
    }

    override fun onMediaClick(album: Album?, item: Item?, adapterPosition: Int) {
        val intent = Intent(this, AlbumPreviewActivity::class.java)
        intent.putExtra(AlbumPreviewActivity.EXTRA_ALBUM, album)
        intent.putExtra(AlbumPreviewActivity.EXTRA_ITEM, item)
        intent.putExtra(BasePreviewActivity.EXTRA_DEFAULT_BUNDLE, mSelectedCollection.dataWithBundle)
        intent.putExtra(BasePreviewActivity.EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable)
        intent.putExtra(BasePreviewActivity.CHECK_STATE, mOriginalChecked)
        startActivityForResult(intent, REQUEST_CODE_PREVIEW)
    }

    override fun provideSelectedItemCollection(): SelectedItemCollection {
        return mSelectedCollection
    }

    override fun capture() {
        if (mMediaStoreCompat != null) {
            mMediaStoreCompat?.dispatchCaptureIntent(this, REQUEST_CODE_CAPTURE)
        }
    }

    companion object {

        const val EXTRA_RESULT_SELECTION = "extra_result_selection"
        const val EXTRA_RESULT_SELECTION_URI = "extra_result_selection_uri"
        const val EXTRA_RESULT_SELECTION_PATH = "extra_result_selection_path"
        const val EXTRA_RESULT_ORIGINAL_ENABLE = "extra_result_original_enable"
        private const val REQUEST_CODE_PREVIEW = 23
        private const val REQUEST_CODE_CAPTURE = 24
        const val CHECK_STATE = "checkState"

        init {
            AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
        }
    }
}
